package utils

import (
	"audio/model"
	sha12 "crypto/sha1"
	"encoding/json"
	"fmt"
	"github.com/gomodule/redigo/redis"
	"io"
	"io/ioutil"
	"net/http"
	"sort"
	"strings"
)

const (
	TokenUrl    = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"
	JsTicketUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi"
	PageDomain  = "audio.phpcenter.cn"
	TokenKey    = "wechat_mp_access_token"
	JsKey       = "wechat_mp_jsapi_ticket"
)

type TokenStruct struct {
	AccessToken string `json:"access_token"`
	ExpiresIn   int    `json:"expires_in"`
}

var (
	TokenData TokenStruct
)

/**
 * 获取全局access_token
 */
func GetAccessToken() string {
	configStruct := struct {
		Project struct {
			Name string `json:"name"`
		} `json:"project"`
	}{}
	GetConfigStruct(&configStruct)
	projectName := configStruct.Project.Name
	redisKey := projectName + "_" + TokenKey

	if token := GetValueFromRedis(redisKey); len(token) > 0 {
		return token
	}

	wxConfig := model.WechatConfig
	url := fmt.Sprintf(TokenUrl, wxConfig.AppId, wxConfig.Secret)
	response, err := http.Get(url)
	CheckError(err)
	defer response.Body.Close()

	data, err := ioutil.ReadAll(response.Body)
	CheckError(err)

	err = json.Unmarshal(data, &TokenData)
	CheckError(err)
	token := TokenData.AccessToken
	_, err = redis.String(RedisConn.Do("setex", redisKey, TokenData.ExpiresIn-200, token))
	CheckError(err)

	return token
}

/**
 * redis 中获取token
 */
func GetValueFromRedis(key string) string {

	reply, err := redis.String(RedisConn.Do("get", key))
	if err == redis.ErrNil {
		return ""
	}
	println(reply)
	if len(reply) > 0 {
		return reply
	}
	return ""
}

/**
 * 创建签名
 */
func makeSignature(timestamp, nonce string) string {
	localToken := model.WechatConfig.Token
	wordsArr := []string{localToken, timestamp, nonce}
	sort.Strings(wordsArr)
	str := strings.Join(wordsArr, "")
	sha1 := sha12.New()
	_, err := io.WriteString(sha1, str)
	CheckError(err)

	return fmt.Sprintf("%x", sha1.Sum(nil))
}

/**
 * 校验签名
 */
func CheckSignature(signatureFrom, timestamp, nonce string) bool {
	signatureGen := makeSignature(timestamp, nonce)
	if signatureFrom != signatureGen {
		return false
	}

	return true
}

/**
 * 获取jsapi ticket
 */
func GetJsTicket() string {
	type Project struct {
		Name string `json:"name"`
	}
	configStruct := struct {
		Project Project `json:"project"`
	}{}
	GetConfigStruct(&configStruct)
	projectName := configStruct.Project.Name
	jsKey := projectName + "_" + JsKey
	ticket := GetValueFromRedis(jsKey)
	if len(ticket) > 0 {
		return ticket
	}

	url := fmt.Sprintf(JsTicketUrl, GetAccessToken())
	response, err := http.Get(url)
	CheckError(err)
	defer response.Body.Close()

	data, err := ioutil.ReadAll(response.Body)
	CheckError(err)
	ticketStruct := struct {
		Errcode   int    `json:"errcode"`
		Errmsg    string `json:"errmsg"`
		Ticket    string `json:"ticket"`
		ExpiresIn int    `json:"expires_in"`
	}{}

	err = json.Unmarshal(data, &ticketStruct)
	CheckError(err)
	ticket = ticketStruct.Ticket
	_, err = redis.String(RedisConn.Do("setex", jsKey, ticketStruct.ExpiresIn-200, ticket))
	CheckError(err)

	return ticket
}

/**
 * 获取js 签名
 */
func GetJsSignature(noncestr, ticket, timestamp, url string) string {
	jsParams := "jsapi_ticket=%s&noncestr=%s&timestamp=%s&url=%s"
	formatedParams := fmt.Sprintf(jsParams, ticket, noncestr, timestamp, url)
	sha1 := sha12.New()
	_, err := io.WriteString(sha1, formatedParams)
	CheckError(err)

	return fmt.Sprintf("%x", sha1.Sum(nil))
}
